package org.swqsbssddqs.shortlink.admin.common.biz.user;


import jakarta.servlet.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.swqsbssddqs.shortlink.admin.common.convention.exception.ClientException;
import org.swqsbssddqs.shortlink.admin.common.convention.exception.ServiceException;
import org.swqsbssddqs.shortlink.admin.config.UserFlowRiskConfiguration;

import java.io.IOException;
import java.rmi.ServerException;
import java.util.List;
import java.util.Optional;

import static org.swqsbssddqs.shortlink.admin.common.convention.error.BaseErrorCode.FLOW_LIMIT_ERROR;

@RequiredArgsConstructor
@Slf4j
public class UserFlowRiskControlFilter implements Filter {
    private final StringRedisTemplate stringRedisTemplate;
    private final UserFlowRiskConfiguration userFlowRiskConfiguration;
    private final static String userFlowRiskFlowControlLua ="lua/user_flow_risk_control.lua";
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        DefaultRedisScript<Long> script = new DefaultRedisScript<>();
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource(userFlowRiskFlowControlLua)));
        redisScript.setResultType(Long.class);
        String username = Optional.ofNullable(UserContext.getUsername()).orElse("other");
        Long execute =null;
        try{

            execute = stringRedisTemplate.execute(redisScript, List.of(username), userFlowRiskConfiguration.getTimeWindow());
        }catch (Exception e){
            log.error("执行用户请求流量限制LUA脚本出错", e);
            throw new ServiceException(FLOW_LIMIT_ERROR);
        }
        if(execute==null||execute>userFlowRiskConfiguration.getMaxAccessCount()){
            throw new ServiceException(FLOW_LIMIT_ERROR);
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }
}
